home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Online / SpeakFreely / src / lwld.c < prev    next >
C/C++ Source or Header  |  2000-05-18  |  50KB  |  1,950 lines

  1. /*
  2.  
  3.             Speak Freely for Unix
  4.                      Look Who's Listening Server
  5.  
  6. */
  7.  
  8. #include "speakfree.h"
  9. #include "version.h"
  10.  
  11. #ifdef THREADS
  12. #include <pthread.h>
  13. #define Lock(x) pthread_mutex_lock(&(x))
  14. #define Unlock(x) pthread_mutex_unlock(&(x))
  15. #define LockConn()  Lock(connLock)
  16. #define UnlockConn() Unlock(connLock)
  17. #else
  18. #define LockConn()
  19. #define UnlockConn()
  20. #endif
  21.  
  22. #define TockTock    120           /* Timeout check frequency, seconds */
  23. #define TimeoutTime 15 * 60          /* No-response timeout interval, seconds */
  24. #define ServiceThreadTimeout    60    /* Service thread timeout interval, seconds  */
  25.  
  26. #define MaxReplyPacket 512          /* Maximum length of reply data */
  27.  
  28. static int sock;              /* Our socket */
  29. static char *prog;              /* Program name */ 
  30.  
  31. static int lwlport = Internet_Port + 2; /* Look Who's Listening port */
  32. static int debugging = FALSE;          /* Debug mode enabled */
  33. static int verbose = FALSE;          /* Show connections/disconnects */
  34. static int prolix = FALSE;          /* Extremely verbose (show queries) */
  35. #ifdef HEXDUMP
  36. static int hexdump = FALSE;          /* Dump received packets in hex ? */
  37. #endif
  38. static char *htmlFile = NULL;          /* HTML file name base */
  39. static char *htmlPrivateFile = NULL;  /* HTML private directory file name base */
  40. static int htmlTime = 1 * 60;          /* HTML file update time */
  41. static time_t htmlLast = 0;          /* HTML last update time */
  42. static int htmlChange = TRUE;          /* Change since last HTML update ? */
  43. static int htmlRefresh = 0;          /* HTML client-pull refresh interval */
  44. #define HTML_REFRESH    "<meta http-equiv=\"Refresh\" content=\"%d\">\n"
  45. static char *message = NULL;          /* Server information message */
  46. static int messagel;              /* Length of server information message */
  47.  
  48. #ifdef THREADS
  49.  
  50. #define ForwarderSleep    30          /* How often to update forwarded hosts */
  51. #define ForwarderMaxQ    15          /* Maximum items in forward queue */
  52.  
  53. struct lwl_queueitem {
  54.     struct lwl_queueitem *next;       /* Next item in LWL queue */
  55.     int q_rll;                  /* Length of message */
  56.     char q_pkt[2];              /* Message body */
  57. };
  58.  
  59. struct forwarder {
  60.     struct forwarder *next;          /* Next forwarder in chain */
  61.     int status;               /* Site status (0 = normal) */
  62.     char *sitename;              /* Site name specification */
  63.     struct in_addr site;          /* Internet address of target host */
  64.     long port;                  /* Destination port on that host */
  65.     pthread_t thread;              /* ID of forwarder thread */
  66.     int queuelen;              /* Length of queue for forwarder */
  67.     struct lwl_queueitem *head, *tail;/* Queue of messages to be forwarded */
  68. };
  69.  
  70. static pthread_attr_t detached;       /* Attributes for our detached threads */
  71. static pthread_mutex_t fwdlistLock = PTHREAD_MUTEX_INITIALIZER;
  72. static struct forwarder *fwdlist = NULL; /* List of forwarding destinations */
  73.  
  74. #define lwl_nsites 1              /* Threaded version driven from list */
  75.  
  76. struct ballOstring {
  77.     struct ballOstring *next, *prev;  /* Forward and back queue links */
  78.     pthread_t thread;              /* Service thread ID */
  79.     time_t startTime;              /* When did thread start ? */
  80.     struct in_addr site;          /* Internet address of requesting site */
  81.     struct service_arg *sa;          /* Service thread argument */
  82. };
  83.  
  84. static struct ballOstring bshead;     /* Ball of string queue head */
  85. static pthread_mutex_t bsLock = PTHREAD_MUTEX_INITIALIZER;
  86.  
  87. #else
  88. static struct sockaddr_in lookhost;   /* Look who's listening host, if any */
  89. static struct in_addr lwl_sites[LWL_MAX_SITES]; /* LWL site addresses */
  90. static long lwl_ports[LWL_MAX_SITES]; /* Ports for LWL hosts */
  91. static int lwl_nsites = 0;          /* Number of LWL sites published on */
  92. #endif
  93.  
  94. struct lwl {
  95.     struct lwl *next;              /* Next connection */
  96.     time_t ltime;              /* Time of last update */
  97.     unsigned long ssrc;           /* Session source descriptor */
  98.     long naddr;               /* Internet address */
  99.     short port;               /* Port address */
  100.     char *cname;              /* Canonical name */ 
  101.     char *name;               /* User name */
  102.     char *email;              /* Electronic mail address */
  103.     char *phone;              /* Telephone number */
  104.     char *loc;                  /* Geographic location */
  105.     char *tool;               /* Application name */
  106. };
  107.  
  108. #ifdef THREADS
  109.                       /* Connection chain critical section */
  110. static pthread_mutex_t connLock = PTHREAD_MUTEX_INITIALIZER;
  111. #endif
  112. static struct lwl *conn = NULL;       /* Chain of current connections */
  113.  
  114. /*  ETIME  --  Edit time and date for log messages.  */
  115.  
  116. static char *etime(gmt)
  117.   int gmt;
  118. {
  119.     struct tm *t;
  120.     time_t clock;
  121.     static char s[20];
  122.  
  123.     time(&clock);
  124.     if (gmt) {
  125.     t = gmtime(&clock);
  126.     } else {
  127.     t = localtime(&clock);
  128.     }
  129.     sprintf(s, "%d-%02d-%02d %02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  130.            t->tm_hour, t->tm_min);
  131.     return s;
  132. }
  133.  
  134. /*  ESTIME  --    Edit short time.  */
  135.  
  136. static char *estime()
  137. {
  138.     struct tm *t;
  139.     time_t clock;
  140.     static char s[20];
  141.  
  142.     time(&clock);
  143.     t = localtime(&clock);
  144.     sprintf(s, "%02d:%02d", t->tm_hour, t->tm_min);
  145.     return s;
  146. }
  147.  
  148. /*  DUPSDESITEM  --  Make a copy of an SDES item and advance the pointer
  149.              past it.  */
  150.  
  151. static char *dupSdesItem(cp)
  152.   char **cp;
  153. {
  154.     char *ip = *cp, *bp;
  155.     int l = ip[1] & 0xFF;
  156.  
  157.     bp = malloc(l + 1);
  158.     if (bp != NULL) {
  159.     bcopy(ip + 2, bp, l);
  160.     bp[l] = 0;
  161.     }
  162.     *cp = ip + l + 2;
  163.     return bp;
  164. }
  165.  
  166. /*  DESTROYLWL    --  Release storage associated with an LWL list item.  */
  167.  
  168. static void destroyLwl(lw)
  169.   struct lwl *lw;
  170. {
  171.     if (lw->cname != NULL) {
  172.     free(lw->cname);
  173.     }
  174.     if (lw->name != NULL) {
  175.     free(lw->name);
  176.     }
  177.     if (lw->email != NULL) {
  178.     free(lw->email);
  179.     }
  180.     if (lw->phone != NULL) {
  181.     free(lw->phone);
  182.     }
  183.     if (lw->loc != NULL) {
  184.     free(lw->loc);
  185.     }
  186.     if (lw->tool != NULL) {
  187.     free(lw->tool);
  188.     }
  189.     free(lw);
  190. }
  191.  
  192. /*  DUMPLWL  --  Dump an LWL on the specified stream.  */
  193.  
  194. static void dumpLwl(fo, lw)
  195.   FILE *fo;
  196.   struct lwl *lw;
  197. {
  198.     struct sockaddr_in s;
  199.  
  200.     s.sin_addr.s_addr = lw->naddr;
  201.     fprintf(fo, "SSRC = %lX IP = %s Port %d %s", lw->ssrc, inet_ntoa(s.sin_addr),
  202.         lw->port, ctime(&(lw->ltime)));
  203.     if (lw->cname != NULL) {
  204.         fprintf(fo, "    CNAME = %s\n", lw->cname);
  205.     }
  206.     if (lw->name != NULL) {
  207.         fprintf(fo, "     NAME = %s\n", lw->name);
  208.     }
  209.     if (lw->email != NULL) {
  210.         fprintf(fo, "    EMAIL = %s\n", lw->email);
  211.     }
  212.     if (lw->phone != NULL) {
  213.         fprintf(fo, "    PHONE = %s\n", lw->phone);
  214.     }
  215.     if (lw->loc != NULL) {
  216.         fprintf(fo, "      LOC = %s\n", lw->loc);
  217.     }
  218.     if (lw->tool != NULL) {
  219.         fprintf(fo, "     TOOL = %s\n", lw->tool);
  220.     }
  221. }
  222.  
  223. #ifdef NEEDED
  224.  
  225. /*  DUMPLWLCHAIN  --  Dump all current connections.  */
  226.  
  227. static void dumpLwlChain(fo)
  228.   FILE *fo;
  229. {
  230.     struct lwl *lw;
  231.  
  232.     LockConn();
  233.     lw = conn;
  234.     fprintf(fo, "\n==========  %s  ==========\n", etime(FALSE));
  235.     while (lw != NULL) {
  236.         fprintf(fo, "\n");
  237.     dumpLwl(fo, lw);
  238.     lw = lw->next;
  239.     }
  240.     UnlockConn();
  241. }
  242. #endif
  243.  
  244. /*  LOGLWL  --    Generate log entry for LWL event.  */
  245.  
  246. static void logLwl(lw, event)
  247.   struct lwl *lw;
  248.   char *event;
  249. {
  250.     char ipport[40], deef[256];
  251.     struct sockaddr_in u;
  252.  
  253.     u.sin_addr.s_addr = lw->naddr;
  254.     sprintf(ipport, "%s:%d", inet_ntoa(u.sin_addr), lw->port);
  255.     sprintf(deef, "%s %s", ipport, lw->email ? lw->email : lw->cname);
  256.     if (lw->name) {
  257.         sprintf(deef + strlen(deef), " (%s)", lw->name);
  258.     }
  259.     printf("%s %s%s\n", estime(), event, deef);
  260. }
  261.  
  262. /*  GARDOL  -- Validity-check an RTCP packet to make sure we don't
  263.            crash if some bozo sends us garbage.  */
  264.  
  265. static int gardol(p, len)
  266.   unsigned char *p;
  267.   int len;
  268. {
  269.     unsigned char *end;
  270.  
  271.     if ((((p[0] >> 6) & 3) != RTP_VERSION) ||       /* Version incorrect ? */
  272.     ((p[0] & 0x20) != 0) ||            /* Padding in first packet ? */
  273.     ((p[1] != RTCP_SR) && (p[1] != RTCP_RR) &&
  274.      (p[1] != RTCP_SDES) && (p[1] != RTCP_BYE) &&
  275.      (p[1] != RTCP_APP))) {            /* Item type valid ? */
  276.     return FALSE;
  277.     }
  278.     end = p + len;
  279.  
  280.     do {
  281.     /* Advance to next subpacket */
  282.     p += (ntohs(*((short *) (p + 2))) + 1) * 4;
  283.     } while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
  284.  
  285.     return p == end;
  286. }
  287.  
  288. /*  MAKEHTML  --  Create an HTML file showing current connections.  If
  289.                   "private" is set, exact-match names are included
  290.           in the HTML file; this allows creation of a non-exported
  291.                   active site file for the system manager's use.  */
  292.  
  293. static void makeHTML(fname, private)
  294.   char *fname;
  295.   int private;
  296. {
  297.     FILE *of;
  298.     char f[132], fn[132];
  299.  
  300.     strcpy(f, fname);
  301.     strcat(f, ".new");
  302.     of = fopen(f, "w");
  303.     if (of != NULL) {
  304.     struct lwl *lw;
  305.  
  306. #define P(x) fprintf(of, x)
  307.  
  308.     LockConn();
  309.     lw = conn;
  310.         P("<html>\n<head>\n");
  311.     if (htmlRefresh > 0) {
  312.         fprintf(of, HTML_REFRESH, htmlRefresh);
  313.     }
  314.         P("<title>\nSpeak Freely: Active Sites\n");
  315.         P("</title>\n</head>\n\n<body>\n<center>\n<h1>");
  316.         P("Speak Freely: Active Sites</h1>\n<h2>");
  317.         fprintf(of, "As of %s UTC</h2>\n</center>\n<p>\n", etime(TRUE));
  318.  
  319.     if (lw == NULL) {
  320.             P("<h2>No sites active.</h2>\n");
  321.     } else {
  322.         int i = 0;
  323.  
  324.         while (lw != NULL) {
  325.                 if (private || ((lw->email == NULL || lw->email[0] != '*') &&
  326.                     (lw->cname[0] != '*'))) {
  327.             i++;
  328.         }
  329.         lw = lw->next;
  330.         }
  331.         lw = conn;
  332.         if (i == 0) {
  333.         /* Fib about number of sites active if all active sites
  334.                    don't want a directory listing. */
  335.                 P("<h2>No sites active.</h2>\n");
  336.         } else {
  337.                 fprintf(of, "<h2>%d site%s active.</h2>\n",
  338.                     i, i == 1 ? "" : "s");
  339.                 P("<pre>\n");
  340.         while (lw != NULL) {
  341.                     if (private || ((lw->email == NULL || lw->email[0] != '*') &&
  342.                         (lw->cname[0] != '*'))) {
  343.             char ipport[40];
  344.             struct tm *lt;
  345.             struct sockaddr_in u;
  346.             char s[384];
  347.  
  348.             lt = gmtime(&lw->ltime);
  349.             u.sin_addr.s_addr = lw->naddr;
  350.                         sprintf(ipport, "%s:%d", inet_ntoa(u.sin_addr), lw->port);
  351.                         sprintf(s, "\n%-24s %-48s %02d:%02d\n", ipport, lw->cname,
  352.                 lt->tm_hour, lt->tm_min);
  353.             outHTML(of, s);
  354.             if (lw->name != NULL) {
  355.                             sprintf(s, "%25s%s\n", "", lw->name);
  356.                 outHTML(of, s);
  357.             }
  358.             if (lw->loc != NULL) {
  359.                             sprintf(s, "%25s%s\n", "", lw->loc);
  360.                 outHTML(of, s);
  361.             }
  362.             if (lw->phone != NULL) {
  363.                             sprintf(s, "%25sPhone:  %s\n", "", lw->phone);
  364.                 outHTML(of, s);
  365.             }
  366.             if (lw->email != NULL) {
  367.                             sprintf(s, "%25sE-mail: %s\n", "", lw->email);
  368.                 outHTML(of, s);
  369.             }
  370.             }
  371.             lw = lw->next;
  372.         }
  373.                 P("</pre>\n");
  374.         }
  375.     }
  376.     UnlockConn();
  377.  
  378.         P("</body>\n</html>\n");
  379.     fclose(of);
  380.     strcpy(fn, fname);
  381.         strcat(fn, ".html");
  382.     rename(f, fn);
  383.     if (debugging) {
  384.             fprintf(stderr, "%s: updated %s\n", prog, fn);
  385.     }
  386.     }
  387. }
  388.  
  389. /*  UPDHTML  --  Update HTML if necessary.  */
  390.  
  391. static void updHTML()
  392. {
  393.     time_t now;
  394.  
  395.     if (((htmlFile != NULL) || (htmlPrivateFile != NULL)) && htmlChange && 
  396.     ((htmlTime <= 0) || (((now = time(NULL)) - htmlLast) > htmlTime))) {
  397.     htmlLast = now;
  398.     htmlChange = FALSE;
  399.     if (htmlFile != NULL) {
  400.         makeHTML(htmlFile, FALSE);
  401.     }
  402.     if (htmlPrivateFile != NULL) {
  403.         makeHTML(htmlPrivateFile, TRUE);
  404.     }
  405.     }
  406. }
  407.  
  408. /*  CHANGED  --  Indicate a change which may require updating
  409.          the HTML file.  */
  410.  
  411. static void changed()
  412. {
  413.     htmlChange = TRUE;
  414. #ifndef THREADS
  415.     updHTML();
  416. #endif
  417. }
  418.  
  419. /*  LCASE  --  Convert a string to lower case.    */
  420.  
  421. static void lcase(s)
  422.   char *s;
  423. {
  424.     while (*s) {
  425.     if (isupper(*s)) {
  426.         *s = tolower(*s);
  427.     }
  428.     s++;
  429.     }
  430. }
  431.  
  432. #ifdef THREADS
  433.  
  434. /*  FORWARDER_THREAD  --  Thread which manages forwarding to a given
  435.               destination.    */
  436.  
  437. static void *forwarder_thread(arg)
  438.   void *arg;
  439. {
  440.     struct forwarder *f = (struct forwarder *) arg;
  441.     struct hostent *h;
  442.     long iadr;
  443.  
  444. #ifdef DBTHREAD
  445. fprintf(stderr, "Started forwarder thread for %s\n", f->sitename);
  446. #endif
  447.     if (isdigit(f->sitename[0]) && (iadr = inet_addr(f->sitename)) != -1) {
  448.     bcopy((char *) &iadr, (char *) (&(f->site)),
  449.           sizeof iadr);
  450.     f->status = 0;
  451.     } else {
  452.     h = gethostbyname(f->sitename);
  453.     if (h != NULL) {
  454.         bcopy((char *) (h->h_addr), 
  455.           (char *) (&(f->site)),
  456.           sizeof(unsigned long));
  457.         f->status = 0;
  458.     } else {
  459.             fprintf(stderr, "%s: warning, forward destination %s unknown.\n",
  460.         prog, f->sitename);
  461.         f->status = -2;
  462.         return NULL;
  463.     }
  464.     }
  465.     if (debugging && f->status == 0) {
  466.         fprintf(stderr, "%s: forwarding to LWL server %s: %s.\n", prog,
  467.         inet_ntoa(f->site), f->sitename);
  468.     }
  469.  
  470.     while (f->status == 0) {
  471.     struct lwl_queueitem *q;
  472.     int sock = -1;
  473.  
  474.     while ((q = f->head) != NULL) {
  475.         int cstat;
  476.         struct sockaddr_in lookhost;
  477.  
  478.         sock = socket(AF_INET, SOCK_STREAM, 0);
  479.         if (sock < 0) {
  480.                 perror("opening forwarding socket");
  481.         break;
  482.         }
  483.  
  484.         lookhost.sin_port = htons(f->port);
  485.         bcopy((char *) (&(f->site)), (char *) &lookhost.sin_addr.s_addr,
  486.           sizeof lookhost.sin_addr.s_addr);
  487.  
  488.         errno = 0;
  489.         do {
  490.         cstat = connect(sock, (struct sockaddr *) &(lookhost), sizeof lookhost);
  491.         if (cstat >= 0) {
  492.             break;
  493.         }
  494.         } while (errno == EINTR);
  495.         if (cstat >= 0) {
  496.         if (send(sock, q->q_pkt, q->q_rll, 0) < 0) {
  497.                     perror("forwarding look who's listening source ID message");
  498.             break;
  499.         } else {
  500.             Lock(fwdlistLock);
  501.             f->head = q->next;
  502.             if (f->head == NULL) {
  503.             f->tail = NULL;
  504.             }
  505.             free(q);
  506.             f->queuelen--;
  507.             if (f->queuelen < 0) {
  508.                         fprintf(stderr, "%s: forward queue underflow to %s.\n", 
  509.                 prog, f->sitename);
  510.             f->queuelen = 0;
  511.             }
  512.             Unlock(fwdlistLock);
  513.             if (debugging) {
  514.                         fprintf(stderr, "%s: forwarded packet to server %s. Queue length now %d.\n",
  515.                 prog, f->sitename, f->queuelen);
  516.             }
  517.         }
  518.         } else {
  519.  
  520.         /* As LWL servers go up and down, failures to connect
  521.            to forwarding destinations are not uncommon.  Further,
  522.            while a server is down, we get here on every packet
  523.            we attempt to forward.  To avoid blithering all
  524.            over the log, we only note such failure if in
  525.            prolix or debugging mode. */
  526.  
  527.         if (prolix || debugging) {
  528.                     perror("connecting forwarding socket");
  529.         }
  530.         break;
  531.         }
  532.         close(sock);
  533.         sock = -1;
  534.     }
  535.  
  536.     /* If we bailed out of the above loop due to an error in
  537.        forwarding the packet, make sure the socket is closed. */
  538.  
  539.     if (sock >= 0) {
  540.         close(sock);
  541.         sock = -1;
  542.     }
  543.     sleep(ForwarderSleep);
  544.     }
  545.  
  546. #ifdef DBTHREAD
  547. fprintf(stderr, "Exited forwarder thread for %s\n", f->sitename);
  548. #endif
  549.     f->status = -1;              /* Forwarder terminated */
  550.     return NULL;
  551. }
  552. #endif
  553.  
  554. /*  FORWARDLIST  --  Parse a list of servers to forward packets to. */
  555.  
  556. static void forwardList(cp)
  557.   char *cp;
  558. {
  559. #ifdef THREADS
  560.     struct forwarder *f;
  561.     char *ep, *np;
  562.  
  563.     while (TRUE) {
  564.     while (*cp != 0 && isspace(*cp)) {
  565.         cp++;
  566.     }
  567.     if (*cp == 0) {
  568.         break;
  569.     }
  570.         if ((np = strchr(cp, ',')) != NULL) {
  571.         *np++ = 0;
  572.     }
  573.     f = (struct forwarder *) malloc(sizeof(struct forwarder));
  574.     if (f != NULL) {
  575.         bzero(f, sizeof(struct forwarder));
  576.         f->status = 1;
  577.         f->sitename = cp;
  578.         f->port = Internet_Port + 2;
  579.             if ((ep = strchr(cp, ':')) != NULL) {
  580.         *ep = 0;
  581.         f->port = atoi(ep + 1);
  582.         }
  583.         f->next = fwdlist;
  584.         fwdlist = f;
  585.         if (pthread_create(&(f->thread), &detached, forwarder_thread, f) != 0) {
  586.                 fprintf(stderr, "%s: Cannot launch forwarder thread for %s: %s",
  587.             prog, cp, strerror(errno));
  588.         free(f);
  589.         }
  590.     } else {
  591.             fprintf(stderr, "%s: out of memory allocating forwarder for %s\n",
  592.         prog, cp);
  593.         break;
  594.     }
  595.     if (np == NULL) {
  596.         break;
  597.     }
  598.     cp = np;
  599.     }
  600. #else
  601.     struct hostent *h;
  602.     char *ep, *np;
  603.     long iadr;
  604.     int n;
  605.  
  606.     lookhost.sin_family = AF_INET;
  607.  
  608.     while (lwl_nsites < LWL_MAX_SITES) {
  609.     n = lwl_nsites;
  610.     while (*cp != 0 && isspace(*cp)) {
  611.         cp++;
  612.     }
  613.     if (*cp == 0) {
  614.         break;
  615.     }
  616.         if ((np = strchr(cp, ',')) != NULL) {
  617.         *np++ = 0;
  618.     }
  619.     lwl_ports[lwl_nsites] = Internet_Port + 2;
  620.         if ((ep = strchr(cp, ':')) != NULL) {
  621.         *ep = 0;
  622.         lwl_ports[lwl_nsites] = atoi(ep + 1);
  623.     }
  624.     if (isdigit(*cp) && (iadr = inet_addr(cp)) != -1) {
  625.         bcopy((char *) &iadr, (char *) (&lwl_sites[lwl_nsites]),
  626.           sizeof iadr);
  627.         lwl_nsites++;
  628.     } else {
  629.         h = gethostbyname(cp);
  630.         if (h != NULL) {
  631.         bcopy((char *) (h->h_addr), 
  632.               (char *) (&lwl_sites[lwl_nsites]),
  633.               sizeof(unsigned long));
  634.         lwl_nsites++;
  635.         } else {
  636.                 fprintf(stderr, "%s: warning, forward destination %s unknown.\n",
  637.             prog, cp);
  638.         }
  639.     }
  640.     if (debugging && lwl_nsites > n) {
  641.             fprintf(stderr, "%s: forwarding to LWL server %s: %s.\n", prog,
  642.         inet_ntoa(lwl_sites[n]), cp);
  643.     }
  644.     if (np == NULL) {
  645.         break;
  646.     }
  647.     cp = np;
  648.     }
  649. #endif
  650. }
  651.  
  652. /*  FORWARDLWLMESSAGE  --  If forwarding is enabled, pass this message
  653.                on to hosts in our forward list, changing the
  654.                packet protocol header to indicate the packet
  655.                was forwarded and appending the IP address
  656.                of the originating host to the end of the packet. */
  657.  
  658. static void forwardLwlMessage(zp, rll, addr)
  659.   char *zp;            /* Packet address */
  660.   int rll;            /* Total packet length (starting at zp) */
  661.   struct in_addr addr;        /* IP address of originator of this packet */
  662. {
  663. #ifndef THREADS
  664.     int i, sock;
  665. #endif
  666.  
  667.     zp[0] |= 0x40;        /* Set forwarded packet flag bit */
  668.     bcopy(&addr, zp + rll, sizeof(struct in_addr));
  669.     rll += sizeof(struct in_addr);
  670. #ifdef THREADS
  671.     {
  672.     struct forwarder *f = fwdlist;
  673.  
  674.     while (f != NULL) {
  675.         if (f->status == 0) {
  676.         if (f->queuelen > ForwarderMaxQ) {
  677.                     fprintf(stderr, "%s: %s queue too long; forward message discarded.\n",
  678.             prog, f->sitename);
  679.         } else {
  680.             struct lwl_queueitem *q = (struct lwl_queueitem *) malloc(
  681.             sizeof(struct lwl_queueitem) + rll);
  682.  
  683.             if (q != NULL) {
  684.             q->next = NULL;
  685.             q->q_rll = rll;
  686.             bcopy(zp, q->q_pkt, rll);
  687.             Lock(fwdlistLock);
  688.             f->queuelen++;
  689.             if (f->head == NULL) {
  690.                 f->head = f->tail = q;
  691.             } else {
  692.                 f->tail->next = q;
  693.                 f->tail = q;
  694.             }
  695.             Unlock(fwdlistLock);
  696.             }
  697.         }
  698.         }
  699.         f = f->next;
  700.     }
  701.     }
  702. #else
  703.     for (i = 0; i < lwl_nsites; i++) {
  704.     if (lwl_ports[i] >= 0) {
  705.         int cstat;
  706.  
  707.         sock = socket(AF_INET, SOCK_STREAM, 0);
  708.         if (sock < 0) {
  709.                 perror("opening forwarding socket");
  710.         continue;
  711.         }
  712.  
  713.         lookhost.sin_port = htons(lwl_ports[i]);
  714.         bcopy((char *) (&lwl_sites[i]), (char *) &lookhost.sin_addr.s_addr,
  715.           sizeof lookhost.sin_addr.s_addr);
  716.  
  717.         errno = 0;
  718.         do {
  719.         cstat = connect(sock, (struct sockaddr *) &(lookhost), sizeof lookhost);
  720.         if (cstat >= 0) {
  721.             break;
  722.         }
  723.         } while (errno == EINTR);
  724.         if (cstat >= 0) {
  725.         if (send(sock, zp, rll, 0) < 0) {
  726.                     perror("forwarding look who's listening source ID message");
  727.         } else {
  728.             if (debugging) {
  729.                         fprintf(stderr, "%s: forwarded packet to server %s.\n",
  730.                 prog, inet_ntoa(lookhost.sin_addr));
  731.             }
  732.         }
  733.         } else {
  734.  
  735.         /* As LWL servers go up and down, failures to connect
  736.            to forwarding destinations are not uncommon.  Further,
  737.            while a server is down, we get here on every packet
  738.            we attempt to forward.  To avoid blithering all
  739.            over the log, we only note such failure if in
  740.            prolix or debugging mode. */
  741.  
  742.         if (prolix || debugging) {
  743.                     perror("connecting forwarding socket");
  744.         }
  745.         }
  746.         close(sock);
  747.     }
  748.     }
  749. #endif
  750. }
  751.  
  752. /*  QUERYMATCH    --  Determing if query matches a given item.  */
  753.  
  754. static int queryMatch(q, l)
  755.   char *q;
  756.   struct lwl *l;
  757. {
  758.     char ts[1024];
  759.     int exact = FALSE;
  760.     char *s;
  761.  
  762.     s = ts;
  763.  
  764.     /* We give preference to an E-mail address, if given, to a
  765.        canonical address since it's the user's best known published
  766.        identity on the net.  This, of course, runs the risk of
  767.        spoofing, but since anybody can send us an RTCP packet with
  768.        whatever cname they like, there's no added security in insisting
  769.        on using it. */
  770.  
  771.     strcpy(s, (l->email == NULL) ? l->cname : l->email);
  772.     lcase(s);
  773.  
  774.     if (*q == '*') {
  775.     exact = TRUE;
  776.     q++;
  777.     }
  778.     if (*s == '*') {
  779.     exact = TRUE;
  780.     s++;
  781.     }
  782.     /* Even if we're using the E-mail name, allow an asterisk on the
  783.        canonical name to require an exact match. */
  784.     if (l->cname[0] == '*') {
  785.     exact = TRUE;
  786.     }
  787.  
  788.     if (exact) {
  789.     return strcmp(s, q) == 0;
  790.     }
  791.  
  792.     if (strstr(s, q)) {
  793.     return TRUE;
  794.     }
  795.     if (l->name != NULL) {
  796.     strcpy(s, l->name);
  797.     lcase(s);
  798.     if (strstr(s, q)) {
  799.        return TRUE;
  800.     }
  801.     }
  802.     return FALSE;
  803. }
  804.  
  805. /*  RELEASE  --  Check for connections who haven't send us an update
  806.          once in the timeout interval and close them.  They
  807.          probably went away without having the courtesy to
  808.          say good-bye.    */
  809.  
  810. static void release()
  811. {
  812.     struct lwl *lw, *llr = NULL, *lf;
  813.     time_t now = time(NULL);
  814.  
  815.     LockConn();
  816.     lw = conn;
  817.     while (lw != NULL) {
  818.     if ((now - lw->ltime) > TimeoutTime) {
  819.         lf = lw;
  820.         if (llr == NULL) {
  821.         conn = lw->next;
  822.         lw = conn;
  823.         } else {
  824.         llr->next = lw->next;
  825.         lw = lw->next;
  826.         }
  827. /*
  828. fprintf(stderr, "\nTiming out:\n");
  829. dumpLwl(stderr, lf);
  830. */
  831.         if (verbose) {
  832.                 logLwl(lf, "Timeout: ");
  833.         }
  834.         htmlChange = TRUE;
  835.         destroyLwl(lf);
  836.     } else {
  837.         llr = lw;
  838.         lw = lw->next;
  839.     }
  840.     }
  841.     UnlockConn();
  842. #ifndef THREADS
  843.     updHTML();                        /* Update HTML if something's changed recently */
  844.     signal(SIGALRM, release);          /* Reset signal to handle timeout (Sys V) */
  845.     alarm(TockTock);              /* Reset the timer */
  846. #endif
  847. }
  848.  
  849. /*  PLUMBER  --  Catch SIGPIPE signal which occurs when remote user
  850.          disconnects before we try to send the reply.  */
  851.  
  852. static void plumber()
  853. {
  854. #ifdef DBTHREAD
  855. fprintf(stderr, "Caught SIGPIPE--continuing.\n");
  856. #endif
  857.     signal(SIGPIPE, plumber);          /* Reset signal just in case */
  858. }
  859.  
  860. /*  EXITING  --  Release socket in case of termination.  */
  861.  
  862. static void exiting()
  863. {
  864. #ifdef DBTHREAD
  865. fprintf(stderr, "Exiting.\n");
  866. #endif
  867.     shutdown(sock, 2);
  868.     close(sock);
  869.     exit(0);
  870. }
  871.  
  872. /*  PROG_NAME  --  Extract program name from argv[0].  */
  873.  
  874. static char *prog_name(arg)
  875.   char *arg;
  876. {
  877.     char *cp = strrchr(arg, '/');
  878.  
  879.     return (cp != NULL) ? cp + 1 : arg;
  880. }
  881.  
  882. /*  USAGE  --  Print how-to-call information.  */
  883.  
  884. static void usage()
  885. {
  886.     V fprintf(stderr, "%s  --  Speak Freely: Look Who's Listening Server.\n", prog);
  887. #ifdef THREADS
  888.     V fprintf(stderr, "               (Multi-threaded version)\n");
  889. #endif
  890.     V fprintf(stderr, "               %s.\n", Relno);
  891.     V fprintf(stderr, "\n");
  892.     V fprintf(stderr, "Usage: %s [options]\n", prog);
  893.     V fprintf(stderr, "Options:\n");
  894.     V fprintf(stderr, "           -D         Debugging output on stderr\n");
  895.     V fprintf(stderr, "           -Fserv,... Forward to listed servers\n");
  896.     V fprintf(stderr, "           -Hpath     Write HTML status on base path\n");
  897.     V fprintf(stderr, "           -Insec     Interval between HTML updates\n");
  898.     V fprintf(stderr, "           -Mfile     Load server message from file\n");
  899.     V fprintf(stderr, "           -Pport     Listen on given port\n");
  900.     V fprintf(stderr, "           -Rnsec     Client-pull HTML refresh every nsec seconds\n");
  901.     V fprintf(stderr, "           -U         Print this message\n");
  902.     V fprintf(stderr, "           -V[V]      List connections and disconnects [-VV: all packets]\n");
  903. #ifdef HEXDUMP
  904.     V fprintf(stderr, "           -X         Dump packets in hex\n");
  905. #endif
  906.     V fprintf(stderr, "           -Zpath     Write HTML private directory on base path\n");
  907.     V fprintf(stderr, "\n");
  908.     V fprintf(stderr, "by John Walker\n");
  909.     V fprintf(stderr, "   http://www.fourmilab.ch/\n");
  910. }
  911.  
  912. /*  ADD_SDES_ITEM  --  Include an SDES item in a reply packet,
  913.                pruning illegal characters and content,
  914.                checking for packet overflow, and updating
  915.                the packet pointer.  */
  916.  
  917. #define addSDES(item, text) add_sdes_item(item, text, &ap)
  918.  
  919. static void add_sdes_item(item, text, app)
  920.   int item;
  921.   char *text;
  922.   char **app;
  923. {
  924.     int l, state;
  925.     char prune[258];
  926.     char *ap = *app, *hp, *op = prune;
  927.  
  928.     /* Copy the text to the "prune" buffer using a simple
  929.        state machine parser, filtering extraneous
  930.        information. */
  931.  
  932.     state = 0;
  933.  
  934.     while (*text) {
  935.     unsigned char ch = (unsigned char) *text++;
  936.  
  937.     if (item == RTCP_SDES_PRIV && op == prune) {
  938.         /* Allow PRIV item binary prefix field to pass. */
  939.         *op++ = (char) ch;
  940.         continue;
  941.     }
  942.  
  943.     /* Discard non-graphic characters (ISO 8859 standard). */
  944.  
  945.         if (!isspace(ch) && (ch < ' ' || (ch > '~' && ch < 161))) {
  946.         continue;
  947.     }
  948.  
  949.     switch (state) {
  950.  
  951.         case 0:              /* Skipping initial white space */
  952.         if (!isspace(ch)) {
  953.             state = 1;
  954.         } else {
  955.             break;
  956.         }
  957.         /* Note fall-through */
  958.  
  959.         case 1:              /* Transcribing to output */
  960. s1:             if (ch == '<') {
  961.                     if ((hp = strchr(text, '>')) != NULL) {
  962.             text = hp + 1;
  963.             if (op > prune && isspace(op[-1])) {
  964.                 state = 2;
  965.             }
  966.             continue;
  967.             }
  968.         }
  969.         if (isspace(ch)) {
  970.                     ch = ' ';         /* Convert all white space into blanks */
  971.             state = 2;
  972.         }
  973.         *op++ = (char) ch;
  974.         break;
  975.  
  976.         case 2:              /* Collapsing multiple white space */
  977.         if (!isspace(ch)) {
  978.             state = 1;
  979.             goto s1;
  980.         }
  981.         break;
  982.     }
  983.     }
  984.     *op = 0;
  985.  
  986.     /* Drop trailing blanks. */
  987.  
  988.     while (strlen(prune) > 0 && isspace(op[-1])) {
  989.     *(--op) = 0;
  990.     }
  991.  
  992.     l = strlen(prune);
  993.     if (l == 0) {
  994.     return;
  995.     } else if (l > 48) {
  996.     int n;
  997.  
  998.     /* String is too long.    Try to trim it at a word boundary,
  999.        but if that fails just brutally lop it off. */
  1000.  
  1001.     for (n = 47; n > 31; n--) {
  1002.         if (isspace(prune[n])) {
  1003.         prune[n] = 0;
  1004.         n = 0;
  1005.         break;
  1006.         }
  1007.     }
  1008.     if (n > 0) {
  1009.         prune[47] = 0;
  1010.     }
  1011.     }
  1012.  
  1013.     *ap++ = item;
  1014.  
  1015.     *ap++ = l = strlen(prune);
  1016.     bcopy(prune, ap, l);
  1017.     ap += l;
  1018.  
  1019.     *app = ap;
  1020. }
  1021.  
  1022. /*  SERVICEPACKET  --  Process a packet from a connection.  */
  1023.  
  1024. static void servicePacket(csock, from)
  1025.   int csock;
  1026.   struct sockaddr_in from;     /* Sending host address */
  1027. {
  1028.     int rll, forward, pvalid;
  1029.     char zp[1024];
  1030.     rtcp_t *rp;
  1031.     short srp;
  1032.     struct lwl *lw;          /* Parsed packet */
  1033.     char *p, *pend;
  1034.     struct sockaddr_in fwdh;
  1035.  
  1036.     forward = FALSE;
  1037.     rll = recv(csock, zp, sizeof zp, 0);
  1038. #ifdef HEXDUMP
  1039.     if (hexdump) {
  1040.         fprintf(stderr, "%s: %d bytes read from socket.\n", prog, rll);
  1041.     xd(stderr, zp, rll, TRUE);
  1042.     }
  1043. #endif
  1044.  
  1045.     /* If packet was forwarded from another server, extract the
  1046.        embedded original source address and make the packet
  1047.        look like it came directly from the sender. */
  1048.  
  1049.     if (rll > 4 && (zp[0] & 0xC0) == 0xC0) {
  1050.     forward = TRUE;
  1051.     zp[0] &= ~0x40;
  1052.     bcopy(zp + (rll - 4), &fwdh.sin_addr, 4);
  1053.     rll -= 4;
  1054.     if (debugging) {
  1055.             fprintf(stderr, "%s: received forwarded packet from %s.\n",
  1056.         prog, inet_ntoa(from.sin_addr));
  1057.     }
  1058.     from.sin_addr = fwdh.sin_addr ;
  1059.     }
  1060.  
  1061.     /* Some version of Speak Freely for Windows don't always
  1062.        pad request packets to a multiple of four bytes.  If
  1063.        this is the case, insert the pad ourselves. */
  1064.  
  1065.     while (((zp[1] & 0xFF) == RTCP_APP) && ((rll & 3) != 0)) {
  1066.     zp[rll++] = 0;
  1067.     }
  1068.  
  1069.     /* Validate this packet.  If it fails the validity check,
  1070.        ignore it do it can't crash the code below. */
  1071.  
  1072.     if (!gardol((unsigned char *) zp, rll)) {
  1073.     if (debugging) {
  1074.             fprintf(stderr, "%s: discarded invalid RTCP packet from %s.\n",
  1075.         prog, inet_ntoa(from.sin_addr));
  1076.     }
  1077.     close(csock);
  1078.     return;
  1079.     }
  1080.  
  1081.     /* Walk through the individual items in a possibly composite
  1082.        packet until we locate an item we're interested in.  This
  1083.        allows us to accept packets that comply with the RTP standard
  1084.        that all RTCP packets begin with an SR or RR.  */
  1085.  
  1086.     p = zp;
  1087.     pend = p + rll;
  1088.     pvalid = FALSE;
  1089.  
  1090.     while ((p < pend) && (p[0] >> 6 & 3) == RTP_VERSION) {
  1091.     int pt = p[1] & 0xFF;
  1092.  
  1093.     if (pt == RTCP_SDES || pt == RTCP_BYE || pt == RTCP_APP) {
  1094.         pvalid = TRUE;
  1095.         break;
  1096.     }
  1097.     /* If not of interest to us, skip to next subpacket. */
  1098.     p += (ntohs(*((short *) (p + 2))) + 1) * 4;
  1099.     }
  1100.  
  1101.     if (!pvalid) {
  1102.     if (debugging) {
  1103.             fprintf(stderr, "%s: discarded RTCP packet with unknown payload from %s.\n",
  1104.         prog, inet_ntoa(from.sin_addr));
  1105.     }
  1106.     close(csock);
  1107.     return;
  1108.     }
  1109.  
  1110.     /* Examine the packet to see what kind of request it is.
  1111.        Note that since all the packets we're interested in can
  1112.        be parsed without knowing their actual length in bytes, we
  1113.        can ignore the possible presence of padding. */
  1114.  
  1115.     rp = (rtcp_t *) p;
  1116.     srp = ntohs(*((short *) p));
  1117.     if (
  1118. #ifdef RationalWorld
  1119.     rp->common.version == RTP_VERSION && /* Version ID correct */
  1120.     rp->common.count == 1
  1121. #else
  1122.     (((srp >> 14) & 3) == RTP_VERSION) &&
  1123.     (((srp >> 8) & 0x1F) == 1)
  1124. #endif
  1125.        ) {
  1126.  
  1127.     switch (
  1128. #ifdef RationalWorld
  1129.         rp->common.pt
  1130. #else
  1131.         srp & 0xFF
  1132. #endif
  1133.            ) {
  1134.  
  1135.         /*    SDES packet.  This is a notification by a listening
  1136.                               that it's just started or is still
  1137.                   listening.  If the host was previously
  1138.                   active we replace the old parameters
  1139.                   with the new in case something has
  1140.                   changed.    The timeout is reset.  Identity
  1141.                   of host is by canonical name, not SSRC,
  1142.                   since the host may have restarted with
  1143.                   a new SSRC without having sent us a BYE.    */
  1144.  
  1145.         case RTCP_SDES:
  1146.  
  1147.         /* Parse the fields out of the SDES packet. */
  1148.  
  1149.         {
  1150.             char *cp = (char *) rp->r.sdes.item,
  1151.              *lp = cp + (ntohs(rp->common.length) * 4);
  1152.             struct lwl *lr, *llr;
  1153.  
  1154.             lw = (struct lwl *) malloc(sizeof(struct lwl));
  1155.             if (lw != NULL) {
  1156.             bzero((char *) lw, sizeof(struct lwl));
  1157.  
  1158.             lw->ssrc = rp->r.sdes.src;
  1159.             lw->naddr = from.sin_addr.s_addr;
  1160.             lw->port = from.sin_port;
  1161.             lw->ltime = time(NULL);
  1162.             if (prolix) {
  1163.                             printf("%s: %s SDES %08lX\n", prog,
  1164.                 inet_ntoa(from.sin_addr), lw->ssrc);
  1165.             }
  1166.             while (cp < lp) {
  1167.                 switch ((*cp) & 0xFF) {
  1168.  
  1169.                 case RTCP_SDES_CNAME:
  1170.                     lw->cname = dupSdesItem(&cp);
  1171.                     break;
  1172.  
  1173.                 case RTCP_SDES_NAME:
  1174.                     lw->name = dupSdesItem(&cp);
  1175.                     break;
  1176.  
  1177.                 case RTCP_SDES_EMAIL:
  1178.                     lw->email = dupSdesItem(&cp);
  1179.                     break;
  1180.  
  1181.                 case RTCP_SDES_PHONE:
  1182.                     lw->phone = dupSdesItem(&cp);
  1183.                     break;
  1184.  
  1185.                 case RTCP_SDES_LOC:
  1186.                     lw->loc = dupSdesItem(&cp);
  1187.                     break;
  1188.  
  1189.                 case RTCP_SDES_TOOL:
  1190.                     lw->tool = dupSdesItem(&cp);
  1191.                     break;
  1192.  
  1193.                 case RTCP_SDES_PRIV:
  1194.                     {
  1195.                     char *zp = dupSdesItem(&cp);
  1196.  
  1197.                     if (zp != NULL) {
  1198.                         if (zp[0] == 1 &&
  1199.                                                 zp[1] == 'P') {
  1200.                         lw->port = atoi(zp + 2);
  1201.                         }
  1202.                         free(zp);
  1203.                     }
  1204.                     }
  1205.                     break;
  1206.  
  1207.                 case RTCP_SDES_END:
  1208.                     cp = lp;
  1209.                     break;
  1210.  
  1211.                 default:
  1212.                     {
  1213.                     char *zp = dupSdesItem(&cp);
  1214.  
  1215.                     if (zp != NULL) {
  1216.                         free(zp);
  1217.                     }
  1218.                     }
  1219.                     break;
  1220.                 }
  1221.             }
  1222.             if (debugging) {
  1223.                 dumpLwl(stderr, lw);
  1224.             }
  1225.  
  1226.             /* Search chain and see if a user with this
  1227.                name is already know.  If so, replace the
  1228.                entry with this one. */
  1229.  
  1230.             if (lw->cname != NULL) {
  1231.                 lr = conn;
  1232.                 llr = NULL;
  1233.  
  1234.                 while (lr != NULL) {
  1235.                 char *p = lw->cname, *q = lr->cname;
  1236.  
  1237.                                 if (*p == '*') {
  1238.                     p++;
  1239.                 }
  1240.                                 if (*q == '*') {
  1241.                     q++;
  1242.                 }
  1243.                 if (strcmp(p, q) == 0) {
  1244.                     lw->next = lr->next;
  1245.                     if (llr == NULL) {
  1246.                     conn = lw;
  1247.                     } else {
  1248.                     llr->next = lw;
  1249.                     }
  1250.                     destroyLwl(lr);
  1251.                     lw = NULL;
  1252.                     break;
  1253.                 }
  1254.                 llr = lr;
  1255.                 lr = lr->next;
  1256.                 }
  1257.  
  1258.                             /* If we didn't find an entry already in the
  1259.                    chain, link in the new entry.  */
  1260.  
  1261.                 if (lw != NULL) {
  1262.                 lw->next = conn;
  1263.                 conn = lw;
  1264.                 if (verbose) {
  1265.                                     logLwl(lw, "Connect: ");
  1266.                 }
  1267.                 changed();
  1268.                 }
  1269.                 if (!forward && lwl_nsites > 0) {
  1270.                 forwardLwlMessage(zp, rll, from.sin_addr);
  1271.                 }
  1272.             } else {
  1273.                 /* Bogus item with no CNAME -- discard. */
  1274.                 if (debugging || verbose) {
  1275.                                 fprintf(stderr, "Bogus SDES with no CNAME.\n");
  1276.                 if (!debugging) {
  1277.                     dumpLwl(stderr, lw);
  1278.                 }
  1279.                 }
  1280.                 destroyLwl(lw);
  1281.             }
  1282.             }
  1283.         }
  1284.         break;
  1285.  
  1286.         /*    BYE packet.  This is sent when a listening host is
  1287.                  ceasing to listen in an orderly manner.
  1288.                  Identity here is by SSRC, since the
  1289.                  host is assumed to have properly announced
  1290.                              itself.  Besides, that's the only ID in
  1291.                  the RTCP BYE packet, so it had darned
  1292.                  well be sufficient.  */
  1293.  
  1294.         case RTCP_BYE:
  1295.         {
  1296.             struct lwl *lr = conn, *llr = NULL;
  1297.  
  1298.             if (prolix) {
  1299.                         printf("%s: %s BYE %08lX\n", prog,
  1300.                 inet_ntoa(from.sin_addr), rp->r.bye.src[0]);
  1301.             }
  1302.             while (lr != NULL) {
  1303.             if (rp->r.bye.src[0] == lr->ssrc) {
  1304.                 if (llr == NULL) {
  1305.                 conn = lr->next;
  1306.                 } else {
  1307.                 llr->next = lr->next;
  1308.                 }
  1309.                 if (debugging) {
  1310.                                 fprintf(stderr, "Releasing:\n");
  1311.                 dumpLwl(stderr, lr);
  1312.                 }
  1313.                 if (verbose) {
  1314.                                 logLwl(lr, "Bye:     ");
  1315.                 }
  1316.                 changed();
  1317.                 destroyLwl(lr);
  1318.                 break;
  1319.             }
  1320.             llr = lr;
  1321.             lr = lr->next;
  1322.             }
  1323.             if (!forward && lwl_nsites > 0) {
  1324.             forwardLwlMessage(zp, rll, from.sin_addr);
  1325.             }
  1326.         }
  1327.         break;
  1328.  
  1329.         /*    Application request packets.  The following application
  1330.         extensions implement the various queries a client can make
  1331.         regarding the current state of the listening host list.  */
  1332.  
  1333.         case RTCP_APP:
  1334.         if (prolix) {
  1335.                     printf("%s: %s APP %.4s\n", prog,
  1336.             inet_ntoa(from.sin_addr), p + 8);
  1337.         }
  1338.  
  1339.         /*  SFlq  --  Pattern match in cname and name and
  1340.                   return matches, up to the maximum
  1341.                   packet size.  If either the query string
  1342.                   or the canonical name begins with an
  1343.                   asterisk, the asterisk(s) is(/are) ignored
  1344.                   and a precise match with the canonical
  1345.                   name is required.  */
  1346.  
  1347.                 if (bcmp(p + 8, "SFlq", 4) == 0) {
  1348.             struct lwl *lr = conn;
  1349.             char b[1500];
  1350.             rtcp_t *rp = (rtcp_t *) b;
  1351.             char *ap, *pap;
  1352.             int l, scandex = 0;
  1353.  
  1354. #ifdef RationalWorld
  1355.             rp->common.version = RTP_VERSION;
  1356.             rp->common.p = 0;
  1357.             rp->common.count = 0;
  1358.             rp->common.pt = RTCP_SDES;
  1359. #else
  1360.             *((short *) rp) = htons((RTP_VERSION << 14) |
  1361.                          RTCP_SDES | (0 << 8));
  1362. #endif
  1363.  
  1364.             ap = (char *) &(rp->r.sdes.src);
  1365.  
  1366.             if (prolix) {
  1367.                         printf("%s: %s query \"%s\"\n", prog, inet_ntoa(from.sin_addr), p + 12);
  1368.             }
  1369.             lcase(p + 12);
  1370.             while (lr != NULL) {
  1371.             if (queryMatch(p + 12, lr)) {
  1372.                 char s[20];
  1373.  
  1374.                 pap = ap;
  1375.                 *((unsigned long *) ap) = lr->ssrc;
  1376.                 ap += sizeof(unsigned long);
  1377.                 addSDES(RTCP_SDES_CNAME, lr->cname +
  1378.                                 (lr->cname[0] == '*' ? 1 : 0));
  1379.  
  1380.                 if (lr->name != NULL) {
  1381.                 addSDES(RTCP_SDES_NAME, lr->name);
  1382.                 }
  1383.  
  1384.                 if (lr->email != NULL) {
  1385.                 addSDES(RTCP_SDES_EMAIL, lr->email +
  1386.                                   (lr->email[0] == '*' ? 1 : 0));
  1387.                 }
  1388.  
  1389.                 if (lr->phone != NULL) {
  1390.                 addSDES(RTCP_SDES_PHONE, lr->phone);
  1391.                 }
  1392.  
  1393.                 if (lr->loc != NULL) {
  1394.                 addSDES(RTCP_SDES_LOC, lr->loc);
  1395.                 }
  1396.  
  1397.                 if (lr->tool != NULL) {
  1398.                 addSDES(RTCP_SDES_TOOL, lr->tool);
  1399.                 }
  1400.  
  1401.                             sprintf(s, "\001P%d", lr->port);
  1402.                 addSDES(RTCP_SDES_PRIV, s);
  1403.  
  1404.                 {
  1405.                 struct sockaddr_in u;
  1406.  
  1407.                 u.sin_addr.s_addr = lr->naddr;
  1408.                                 sprintf(s, "\001I%s", inet_ntoa(u.sin_addr));
  1409.                 addSDES(RTCP_SDES_PRIV, s);
  1410.                 }
  1411.  
  1412.                             sprintf(s, "\001T%lu", lr->ltime);
  1413.                 addSDES(RTCP_SDES_PRIV, s);
  1414.  
  1415. #ifdef NEEDED
  1416.                             /* If we're over the packet size limit,
  1417.                                let the user know there's more to be
  1418.                    retrieved starting at the given offset. */
  1419.  
  1420.                 if ((ap - b) > MaxReplyPacket) {
  1421.                                 sprintf(s, "\001M%d", scandex);
  1422.                 addSDES(RTCP_SDES_PRIV, s);
  1423.                 }
  1424. #endif
  1425.                 *ap++ = RTCP_SDES_END;
  1426.  
  1427.                 /* Pad to next 32 bit boundary. */
  1428.  
  1429.                 while (((ap - b) & 3) != 0) {
  1430.                 *ap++ = RTCP_SDES_END;
  1431.                 }
  1432.                 if ((ap - b) > MaxReplyPacket) {
  1433.                 ap = pap;
  1434.                 break;
  1435.                 }
  1436. #ifdef RationalWorld
  1437.                 rp->common.count++;
  1438. #else
  1439.                 (((unsigned char *) rp)[0])++;
  1440. #endif
  1441.             }
  1442.             lr = lr->next;
  1443.             scandex++;
  1444.             }
  1445.  
  1446.             l = ap - b;
  1447.  
  1448.             rp->common.length = htons(((l + 3) / 4) - 1);
  1449.             l = (ntohs(rp->common.length) + 1) * 4;
  1450. #ifdef HEXDUMP
  1451.             if (hexdump) {
  1452.                         fprintf(stderr, "%s: %d bytes sent to socket.\n", prog, l);
  1453.             xd(stderr, b, l, TRUE);
  1454.             }
  1455. #endif
  1456.             if (send(csock, b, l, 0) < 0) {
  1457.                         perror("sending query match reply");
  1458.             }
  1459.         }
  1460.  
  1461.                 /*  SFms  --  Retrieve the server's information
  1462.                               message, if any.  If the server doesn't
  1463.                   publish a message, a null string is
  1464.                   returned in the reply packet.  */
  1465.  
  1466.                 else if (bcmp(p + 8, "SFms", 4) == 0) {
  1467. #ifdef HEXDUMP
  1468.             if (hexdump) {
  1469.                         fprintf(stderr, "%s: %d bytes sent to socket.\n",
  1470.                 prog, messagel);
  1471.             xd(stderr, message, messagel, TRUE);
  1472.             }
  1473. #endif
  1474.             if (prolix) {
  1475.                         printf("%s: %s server message request\n", prog, inet_ntoa(from.sin_addr));
  1476.             }
  1477.             if (send(csock, message, messagel, 0) < 0) {
  1478.                         perror("sending server message");
  1479.             }
  1480.         }
  1481.         break;
  1482.  
  1483.         default:
  1484.         if (debugging || verbose) {
  1485.                     fprintf(stderr, "Bogus payload type %d\n",
  1486. #ifdef RationalWorld
  1487.                   rp->common.pt
  1488. #else
  1489.                   ((unsigned char *) rp)[1]
  1490. #endif
  1491.                );
  1492.         }
  1493.         break;
  1494.     }
  1495.     }
  1496.     close(csock);
  1497. }
  1498.  
  1499. #ifdef THREADS
  1500.  
  1501. /*  Thread processing functions.  */
  1502.  
  1503. #ifdef DBTHREAD
  1504.  
  1505. /*  EDIT_THREAD  --  Edit information about a service thread from
  1506.              its packet in the ballOstring chain.  */
  1507.  
  1508. static char *edit_thread(b)
  1509.   struct ballOstring *b;
  1510. {
  1511.     static char s[80];
  1512.  
  1513.     sprintf(s, "%d %s %s", b->thread, inet_ntoa(b->site), ctime(&b->startTime));
  1514.     s[strlen(s) - 1] = 0;
  1515.     return s;
  1516. }
  1517. #endif
  1518.  
  1519. /*  TIMEOUT_THREAD  --    Handle timeout of sites that go away without
  1520.                         sending a "Bye" message.  */
  1521.  
  1522. static void *timeout_thread(arg)
  1523.   void *arg;
  1524. {
  1525.     long ct;
  1526.     struct ballOstring *b;
  1527.  
  1528. #ifdef DBTHREAD
  1529. fprintf(stderr, "Timeout thread running\n");
  1530. #endif
  1531.     while (TRUE) {
  1532.     sleep(120);              /* Wait for next awake interval */
  1533.     time(&ct);
  1534. #ifdef DBTHREAD
  1535. fprintf(stderr, "Timeout thread scanning connections\n");
  1536. #endif
  1537.     Lock(bsLock);
  1538.     b = bshead.next;
  1539.     while (b != &bshead) {
  1540. #ifdef DBTHREAD
  1541. fprintf(stderr, "    Thread %s\n", edit_thread(b));
  1542. #endif
  1543.         if ((b->startTime + ServiceThreadTimeout) < ct) {
  1544. #ifdef DBTHREAD
  1545. fprintf(stderr, "               Kill sent due to timeout.\n");
  1546. #endif
  1547.         pthread_kill(b->thread, SIGUSR1);
  1548.         }
  1549.         b = b->next;
  1550.     }
  1551.     Unlock(bsLock);
  1552.     release();
  1553.     }
  1554. }
  1555.  
  1556. /*  HTML_THREAD  --  Update the HTML database(s) if something has
  1557.              changed since the last time.  */
  1558.  
  1559. static void *html_thread(arg)
  1560.   void *arg;
  1561. {
  1562. #ifdef DBTHREAD
  1563. fprintf(stderr, "HTML update thread running\n");
  1564. #endif
  1565.     while (TRUE) {
  1566. #ifdef DBTHREAD
  1567. fprintf(stderr, "HTML update thread examining connections\n");
  1568. #endif
  1569.     updHTML();
  1570.  
  1571.     /* In the threaded version, consider every 15 seconds as
  1572.            equivalent to "immediate update on every change".
  1573.        We could accomplish immediate update with a
  1574.        semaphore signalling mechanism, but that would
  1575.        cause the threaded and non-threaded versions to
  1576.        diverge much more.  Besides, nobody runs in immediate
  1577.        update mode anyway, as far as I can determine. */
  1578.  
  1579.     sleep((unsigned int) (htmlTime <= 0 ? 15 : htmlTime));
  1580.     }
  1581. }
  1582.  
  1583. /*  SERVICE_THREAD  --    Thread to process user packet.    One of
  1584.             these is created every time a connection is
  1585.             accepted.  */
  1586.  
  1587. struct service_arg {
  1588.     int sa_csock;
  1589.     struct sockaddr_in sa_from;
  1590.     struct ballOstring *sa_b;
  1591. };
  1592.  
  1593. static void killserv()
  1594. {
  1595.     pthread_t us = pthread_self();
  1596.     struct ballOstring *b;
  1597. #ifdef DBTHREAD
  1598. fprintf(stderr, "Gaaaak!!!  Killserv received by thread %d.\n", us);
  1599. #endif
  1600.  
  1601.     /* We're being killed by the timeout handler.  Search for
  1602.        our entry in the ballOstring chain. */
  1603.  
  1604.     Lock(bsLock);
  1605.     b = bshead.next;
  1606.     while (b != &bshead) {
  1607.     if (b->thread == us) {
  1608.  
  1609.         /* Dechain from active thread list. */
  1610.  
  1611.         b->prev->next = b->next;
  1612.         b->next->prev = b->prev;
  1613.         break;
  1614.     }
  1615.     b = b->next;
  1616.     }
  1617.     Unlock(bsLock);
  1618.     if (b != &bshead) {
  1619.     if (b->sa->sa_csock != -1) {
  1620.         close(b->sa->sa_csock);
  1621.     }
  1622. #ifdef DBTHREAD
  1623. fprintf(stderr, "Thread killed by timeout: %s\n", edit_thread(b));
  1624. #endif
  1625.     free(b->sa);
  1626.     free(b);
  1627.     pthread_exit(NULL);
  1628.     } else {
  1629. #ifdef DBTHREAD
  1630. fprintf(stderr, "Oops!!!  Timeout kill request to thread %d, not in ballOstring.\n", us);
  1631. #endif
  1632.     }
  1633. }
  1634.  
  1635. static void *service_thread(arg)
  1636.   void *arg;
  1637. {
  1638.     struct service_arg *sa = arg;
  1639.  
  1640. #ifdef DBTHREAD
  1641. fprintf(stderr, "Server thread %d for host %s launched\n", pthread_self(), inet_ntoa(sa->sa_from.sin_addr));
  1642. #endif
  1643.     signal(SIGUSR1, killserv);           /* Set signal to handle timeout */
  1644.     sa->sa_b->thread = pthread_self();
  1645.     servicePacket(sa->sa_csock, sa->sa_from);
  1646. #ifdef DBTHREAD
  1647. fprintf(stderr, "Server thread %d for host %s exiting\n", pthread_self(), inet_ntoa(sa->sa_from.sin_addr));
  1648. #endif
  1649.  
  1650.     /* Dechain this thread's item from the ballOstring list. */
  1651.  
  1652. #ifdef DBTHREAD
  1653. fprintf(stderr, "Thread exiting: %s\n", edit_thread(sa->sa_b));
  1654. #endif
  1655.     Lock(bsLock);
  1656.     sa->sa_b->prev->next = sa->sa_b->next;
  1657.     sa->sa_b->next->prev = sa->sa_b->prev;
  1658.     free(sa->sa_b);
  1659.     Unlock(bsLock);
  1660.     free(sa);                  /* Release request packet */
  1661.     pthread_exit(NULL);
  1662. }
  1663. #endif
  1664.  
  1665. /*  Main program.  */
  1666.  
  1667. main(argc, argv)
  1668.   int argc;
  1669.   char *argv[];
  1670. {
  1671.     int i, length;
  1672.     struct sockaddr_in name;
  1673. #ifdef THREADS
  1674.     pthread_t timeout_tid, html_tid;
  1675.  
  1676.     pthread_attr_init(&detached);
  1677.     pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED);
  1678.     pthread_attr_setstacksize(&detached, (size_t) 65536);
  1679.     bshead.next = bshead.prev = &bshead;
  1680. #endif
  1681.  
  1682.     /*    Process command line options.  */
  1683.  
  1684.     prog = prog_name(argv[0]);
  1685.  
  1686. #ifdef PRUNEFACE
  1687.     {    /* Interctive debugging of text pruning logic. */
  1688.     char s[132], p[132];
  1689.     char *zap;
  1690.  
  1691.     while (TRUE) {
  1692.             printf("--> ");
  1693.         if (fgets(s, sizeof s, stdin) == NULL) {
  1694.         break;
  1695.         }
  1696.         zap = p;
  1697.         add_sdes_item(1, s, &zap);
  1698.         *zap = 0;
  1699.             printf(    "\"%s\"\n", p + 2);
  1700.     }
  1701.     exit(0);
  1702.     }
  1703. #endif
  1704.  
  1705.     for (i = 1; i < argc; i++) {
  1706.     char *op, opt;
  1707.  
  1708.     op = argv[i];
  1709.         if (*op == '-') {
  1710.         opt = *(++op);
  1711.         if (islower(opt)) {
  1712.         opt = toupper(opt);
  1713.         }
  1714.  
  1715.         switch (opt) {
  1716.  
  1717.                 case 'D':             /* -D  --  Debug output to stderr */
  1718.             debugging = TRUE;
  1719.             break;
  1720.  
  1721.                 case 'F':             /* -Fserv,...  --  Forward to listed servers. */
  1722.             forwardList(op + 1);
  1723.             break;
  1724.  
  1725.                 case 'H':             /* -Hname  --  HTML file name base path */
  1726.             htmlFile = op + 1;
  1727.             break;
  1728.  
  1729.                 case 'I':             /* -Isec  --  Interval between HTML updates */
  1730.             htmlTime = atoi(op + 1);
  1731.             break;
  1732.  
  1733.                 case 'M':             /* -Mfile  --  Load server message from file */
  1734.             {
  1735.                         FILE *fp = fopen(op + 1, "r");
  1736.             long fl;
  1737.  
  1738.             if (fp == NULL) {
  1739.                             fprintf(stderr, "%s: can't open server message file %s\n", prog, op + 1);
  1740.                 return 2;
  1741.             }
  1742.             fseek(fp, 0L, 2);
  1743.             fl = ftell(fp);
  1744.             rewind(fp);
  1745.             messagel = ((int) fl) + 13;
  1746.             message = (char *) malloc(messagel);
  1747.             if (message != NULL) {
  1748.                 rtcp_t *rp = (rtcp_t *) message;
  1749.  
  1750. #ifdef RationalWorld
  1751.                 rp->common.version = RTP_VERSION;
  1752.                 rp->common.p = 0;
  1753.                 rp->common.count = 1;
  1754.                 rp->common.pt = RTCP_APP;
  1755. #else
  1756.                 *((short *) rp) = htons((RTP_VERSION << 14) |
  1757.                             RTCP_APP | (1 << 8));
  1758. #endif
  1759.                 rp->r.sdes.src = 0;
  1760.                             bcopy("SFmr", message + 8, 4);
  1761.                 fread(message + 12, (int) fl, 1, fp);
  1762.                 message[messagel - 1] = 0;
  1763.             }
  1764.             fclose(fp);
  1765.             }
  1766.             break;
  1767.  
  1768.                 case 'P':             /* -Pport  --  Port to listen on */
  1769.             lwlport = atoi(op + 1);
  1770.             break;
  1771.  
  1772.                 case 'R':             /* -Rnsec  --  Interval between HTML client-pull updates */
  1773.             htmlRefresh = atoi(op + 1);
  1774.             break;
  1775.  
  1776.                 case 'U':             /* -U  --  Print usage information */
  1777.                 case '?':             /* -?  --  Print usage information */
  1778.             usage();
  1779.             return 0;
  1780.  
  1781.                 case 'V':             /*  -V  -- Show connects/disconnects */
  1782.             verbose = TRUE;
  1783.                     if (op[1] == 'v' || op[1] == 'V') {
  1784.             prolix = TRUE;
  1785.             }
  1786.             break;
  1787.  
  1788. #ifdef HEXDUMP
  1789.                 case 'X':             /* -X  --  Dump packets in hex */
  1790.             hexdump = TRUE;
  1791.             break;
  1792. #endif
  1793.  
  1794.                 case 'Z':             /* -Zname  --  HTML private file name base path */
  1795.             htmlPrivateFile = op + 1;
  1796.             break;
  1797.         }
  1798.     } else {
  1799.         usage();
  1800.         return 2;
  1801.     }
  1802.     }
  1803.  
  1804.     /* If no server message has been loaded, create a void one. */
  1805.  
  1806.     if (message == NULL) {
  1807.     rtcp_t *rp;
  1808.  
  1809.     messagel = 13;
  1810.     message = (char *) malloc(messagel);
  1811.     rp = (rtcp_t *) message;
  1812.  
  1813. #ifdef RationalWorld
  1814.     rp->common.version = RTP_VERSION;
  1815.     rp->common.p = 0;
  1816.     rp->common.count = 1;
  1817.     rp->common.pt = RTCP_APP;
  1818. #else
  1819.     *((short *) rp) = htons((RTP_VERSION << 14) | RTCP_APP | (1 << 8));
  1820. #endif
  1821.     rp->r.sdes.src = 0;
  1822.         bcopy("SFmr", message + 8, 4);
  1823.     message[messagel - 1] = 0;
  1824.     }
  1825.  
  1826.  
  1827.     /* Create the socket from which to read */
  1828.  
  1829.     sock = socket(AF_INET, SOCK_STREAM, 0);
  1830.     if (sock < 0) {
  1831.         perror("opening stream socket");
  1832.     return 1;
  1833.     }
  1834.  
  1835.     /* Create name with wildcards. */
  1836.  
  1837.     name.sin_family = AF_INET;
  1838.     name.sin_addr.s_addr = INADDR_ANY;
  1839.     name.sin_port = htons(lwlport);
  1840.     if (bind(sock, (struct sockaddr *) &name, sizeof name) < 0) {
  1841.         perror("binding stream socket");
  1842.     return 1;
  1843.     }
  1844.  
  1845.     signal(SIGHUP, exiting);          /* Set signal to handle termination */
  1846.     signal(SIGINT, exiting);          /* Set signal to handle termination */
  1847.     signal(SIGTERM, exiting);          /* Set signal to handle termination */
  1848.  
  1849.     signal(SIGPIPE, plumber);         /* Catch "broken pipe" signals from disconnects */
  1850.  
  1851.     if (listen(sock, 25) < 0) {
  1852.         perror("calling listen for socket");
  1853.     }
  1854.  
  1855.     /* Find assigned port value and print it. */
  1856.  
  1857.     length = sizeof(name);
  1858.     if (getsockname(sock, (struct sockaddr *) &name, &length) < 0) {
  1859.         perror("getting socket name");
  1860.     return 1;
  1861.     }
  1862. #ifdef SHOW_SOCKET
  1863.     fprintf(stderr, "%s: socket port #%d\n", prog, ntohs(name.sin_port));
  1864. #endif
  1865.  
  1866. #ifdef THREADS
  1867.     pthread_create(&timeout_tid, &detached, timeout_thread, NULL);
  1868.     if (htmlFile != NULL || htmlPrivateFile != NULL) {
  1869.     pthread_create(&html_tid, &detached, html_thread, NULL);
  1870.     }
  1871. #else
  1872.     signal(SIGALRM, release);          /* Set signal to handle timeout */
  1873.     alarm(TockTock);              /* Set alarm clock to purge idle hosts */
  1874. #endif
  1875.     changed();                  /* Create initial HTML file */
  1876.     setlinebuf(stdout);           /* Set stdout to line buffering for log */
  1877.  
  1878.     /* Process requests from the socket. */
  1879.  
  1880.     while (TRUE) {
  1881.     int csock;
  1882.     struct sockaddr_in from;      /* Sending host address */
  1883.     int fromlen;              /* Length of sending host address */
  1884. #ifdef THREADS
  1885.     struct service_arg *sap;
  1886.     pthread_t service_tid;
  1887. #endif
  1888.  
  1889.     errno = 0;
  1890.     do {
  1891.         fromlen = sizeof from;
  1892.         csock = accept(sock, (struct sockaddr *) &from, &fromlen);
  1893. #ifdef DBTHREAD
  1894. fprintf(stderr, "Accept %d\n", csock);
  1895. #endif
  1896.         if (csock >= 0) {
  1897.         break;
  1898.         }
  1899.     } while (errno == EINTR);
  1900.     if (csock < 0) {
  1901.             perror("accepting connection to socket");
  1902.         continue;
  1903.     }
  1904.     if (prolix) {
  1905.             printf("%s: %s accept\n", prog, inet_ntoa(from.sin_addr));
  1906.     }
  1907. #ifdef THREADS
  1908.     sap = (struct service_arg *) malloc(sizeof(struct service_arg));
  1909.     if (sap != NULL) {
  1910.         struct ballOstring *b;
  1911.  
  1912.         sap->sa_csock = csock;
  1913.         sap->sa_from = from;
  1914.         b = (struct ballOstring *) malloc(sizeof(struct ballOstring));
  1915.         if (b != NULL) {
  1916.         sap->sa_b = b;
  1917.         b->sa = sap;
  1918.         Lock(bsLock);
  1919.         b->next = bshead.next;
  1920.         b->prev = &bshead;
  1921.         bshead.next = b;
  1922.         b->next->prev = b;
  1923.         b->thread = -1;
  1924.         time(&(b->startTime));
  1925.         b->site = from.sin_addr;
  1926.         Unlock(bsLock);
  1927.         if (pthread_create(&service_tid, &detached, service_thread, sap) != 0) {
  1928.                     fprintf(stderr, "%s: Cannot launch server thread for request from %s: %s",
  1929.             prog, inet_ntoa(from.sin_addr), strerror(errno));
  1930.             close(csock);
  1931.         }
  1932.         } else {
  1933.         free(sap);
  1934.                 fprintf(stderr, "Unable to allocate memory for ballOstring packet.\n");
  1935.         close(csock);
  1936.         }
  1937.     } else {
  1938.             fprintf(stderr, "Unable to allocate memory for service_arg packet.\n");
  1939.         close(csock);
  1940.     }
  1941. #else
  1942.     servicePacket(csock, from);
  1943. #endif
  1944.     }
  1945. #ifdef MEANS_OF_EXIT
  1946.     close(sock);
  1947.     return 0;
  1948. #endif
  1949. }
  1950.